// not meant to be read top to bottom, but rather following the function calls, starting from main

#include <vector> // this is about vector
#include <type_traits> // for checking results

using std::vector;

// foreshadowing~~~
template <typename T>
class wrapper : public vector<T>
{
	using vector<T>::vector;
};
// whatever, proof of concept, dunno how to do this guide properly
template <typename First, typename... Rest> wrapper(First, Rest...) -> wrapper<First>;
// this one is the important one that displaces the copy constructor
template <typename C> wrapper(wrapper<C>) -> wrapper<wrapper<C>>;

int main()
{
	// everyone knows this annoying and confusing thing about std::vector, and containers in general
	{
		vector<int> x;
		vector y{x}; // this is a vector<int>
		static_assert(std::is_same_v<decltype(y), vector<int>>);
		vector z{x,x}; // this is a vector<vector<int>>
		static_assert(std::is_same_v<decltype(z), vector<std::vector<int>>>);
	}
	// while they both look the same


	// copy constructor must not participate in type deduction and both of y and z must wrap, cause from type system perspective vector is in fact a wrapper
	{
		wrapper<int> x; // clearly ask to wrap an int
		wrapper y{x}; // also clearly asking to wrap whatever x is so this should be wrapper<wrapper<int>>
		static_assert(std::is_same_v<decltype(y), wrapper<wrapper<int>>>);
		wrapper z{x,x}; // again obviously we are now wrapping two things - again wrapper<wrapper<int>>
		static_assert(std::is_same_v<decltype(z), wrapper<wrapper<int>>>);
		// "but what if I want a copy?"
		// what do you mean you want a copy?
		// you want it deduced?
		auto c = x; // <- well then ask for it to be deduced
		static_assert(std::is_same_v<decltype(c), wrapper<int>>);
		wrapper<int> d = c; // <- otherwise just ask for it directly
		static_assert(std::is_same_v<decltype(d), wrapper<int>>);
	}

	return 0;
}
